﻿using ArcGIS.Core.CIM;
using ArcGIS.Core.Data;
using ArcGIS.Core.Geometry;
using ArcGIS.Core.Internal.CIM;
using ArcGIS.Desktop.Core;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Desktop.Internal.Framework.Utilities;
using ArcGIS.Desktop.Layouts;
using ArcGIS.Desktop.Mapping;
using Aspose.Cells;
using Aspose.Words;
using CCTool.Scripts.Manager;
using CCTool.Scripts.ToolManagers;
using CCTool.Scripts.ToolManagers.Extensions;
using CCTool.Scripts.ToolManagers.Managers;
using MathNet.Numerics;
using MathNet.Numerics.LinearAlgebra.Factorization;
using NPOI.POIFS.Crypt.Dsig;
using NPOI.SS.Formula.Functions;
using NPOI.SS.Formula.PTG;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using static System.Net.Mime.MediaTypeNames;
using System.Xml.Linq;
using MessageBox = System.Windows.Forms.MessageBox;
using Polygon = ArcGIS.Core.Geometry.Polygon;
using QueryFilter = ArcGIS.Core.Data.QueryFilter;
using Range = Aspose.Cells.Range;
using SpatialReference = ArcGIS.Core.Geometry.SpatialReference;
using TextElement = ArcGIS.Desktop.Layouts.TextElement;
using NPOI.Util;
using System.Security.Cryptography;
using static System.Runtime.InteropServices.JavaScript.JSType;
using Aspose.Cells.Drawing;
using Envelope = ArcGIS.Core.Geometry.Envelope;

namespace CCTool.Scripts.CusTool4
{
    /// <summary>
    /// Interaction logic for CreateZDT.xaml
    /// </summary>
    public partial class CreateZDT : ArcGIS.Desktop.Framework.Controls.ProWindow
    {
        // 工具设置标签
        readonly string toolSet = "CreateZDT";
        public CreateZDT()
        {
            InitializeComponent();

            // 初始化参数选项
            textFolderPath.Text = BaseTool.ReadValueFromReg(toolSet, "outFolder");
            textZTSJ.Text = BaseTool.ReadValueFromReg(toolSet, "ztsj", "2025年1月21日");
            textZTR.Text = BaseTool.ReadValueFromReg(toolSet, "ztr", "张三");
            textSHSJ.Text = BaseTool.ReadValueFromReg(toolSet, "shsj", "2025年1月21日");
            textSHR.Text = BaseTool.ReadValueFromReg(toolSet, "shr", "李四");
            textDW.Text = BaseTool.ReadValueFromReg(toolSet, "dw", "xx股份有限公司");

        }

        // 更新默认字段
        public async void UpdataField()
        {
            string ly = combox_fc.ComboxText();

            // 初始化参数选项
            await UITool.InitLayerFieldToComboxPlus(combox_qlr, ly, "QLR", "string");
            await UITool.InitLayerFieldToComboxPlus(combox_zddm, ly, "ZDDM", "string");
            await UITool.InitLayerFieldToComboxPlus(combox_zdmj, ly, "ZDMJ", "float");
            await UITool.InitLayerFieldToComboxPlus(combox_tfh, ly, "TFH", "string");


        }


        // 定义一个进度框
        private ProcessWindow processwindow = null;
        string tool_name = "批量生成宗地图(醉)";

        private void combox_fc_DropDown(object sender, EventArgs e)
        {
            UITool.AddFeatureLayersToComboxPlus(combox_fc);
        }

        private void openFolderButton_Click(object sender, RoutedEventArgs e)
        {
            textFolderPath.Text = UITool.OpenDialogFolder();
        }

        // 获取字段值，如无则为""
        private string GetFieldValue(Feature feature, string fieldName)
        {
            string result = "";

            if (fieldName is not null && fieldName != "")
            {
                result = feature[fieldName]?.ToString();

                if (fieldName is null)
                {
                    result = "";
                }
            }

            return result;
        }


        private async void btn_go_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                string defGDB = Project.Current.DefaultGeodatabasePath;

                // 参数获取
                string in_fc = combox_fc.ComboxText();
                string in_sd = combox_sd.ComboxText();
                string outFolder = textFolderPath.Text;


                string field_qlr = combox_qlr.ComboxText();
                string field_zddm = combox_zddm.ComboxText();
                string field_tfh = combox_tfh.ComboxText();
                string field_zdmj = combox_zdmj.ComboxText();

                string ztsj = textZTSJ.Text;
                string shsj = textSHSJ.Text;
                string ztr = textZTR.Text;
                string shr = textSHR.Text;
                string dw = textDW.Text;

                // 判断参数是否选择完全
                if (in_fc == "" || outFolder == "")
                {
                    MessageBox.Show("有必选参数为空！！！");
                    return;
                }

                // 写入本地
                BaseTool.WriteValueToReg(toolSet, "outFolder", outFolder);
                BaseTool.WriteValueToReg(toolSet, "ztsj", ztsj);
                BaseTool.WriteValueToReg(toolSet, "shsj", shsj);
                BaseTool.WriteValueToReg(toolSet, "ztr", ztr);
                BaseTool.WriteValueToReg(toolSet, "shr", shr);
                BaseTool.WriteValueToReg(toolSet, "dw", dw);

                // 打开进度框
                ProcessWindow pw = UITool.OpenProcessWindow(processwindow, tool_name);
                pw.AddMessageTitle(tool_name);

                Close();

                await QueuedTask.Run(() =>
                {
                    pw.AddMessageStart("创建界址点、界址线等要素");
                    // 获取目标FeatureLayer
                    FeatureLayer featurelayer = in_fc.TargetFeatureLayer();
                    // 确保要素类的几何类型是多边形
                    if (featurelayer.ShapeType != esriGeometryType.esriGeometryPolygon)
                    {
                        // 如果不是多边形类型，则输出错误信息并退出函数
                        MessageBox.Show("该要素类不是多边形类型。");
                        return;
                    }

                    // 创建文件夹
                    string targetFolder = $@"{outFolder}\{featurelayer.Name}";
                    DirTool.CreateFolder(targetFolder);

                    // 创建界址点界址线
                    string point = $@"{defGDB}\point";
                    string polyline = $@"{defGDB}\polyline";
                    ComboTool.CreateBoundaryPoint(in_fc, point, 3, false);
                    ComboTool.CreateBoundaryPolyline(in_fc, polyline);

                    // 出图
                    // 获取LayoutProjectItem
                    string layoutName = "宗地图";
                    LayoutProjectItem layoutItem = Project.Current.GetItems<LayoutProjectItem>().FirstOrDefault(item => item.Name.Equals(layoutName));
                    Layout layout = layoutItem.GetLayout();            // 获取Layout                         
                    MapFrame mf = layout.FindElement("地图框") as MapFrame;             // 获取主地图框
                    Map map = mf.Map;                         // 获取主地图

                    FeatureLayer zdLayer = map.GetLayersAsFlattenedList().FirstOrDefault(l => l.Name == "宗地") as FeatureLayer;
                    FeatureLayer pointLayer = map.GetLayersAsFlattenedList().FirstOrDefault(l => l.Name == "界址点") as FeatureLayer;
                    FeatureLayer polylineLayer = map.GetLayersAsFlattenedList().FirstOrDefault(l => l.Name == "界址线") as FeatureLayer;

                    FeatureLayer sdLayer = map.GetLayersAsFlattenedList().FirstOrDefault(l => l.Name == "三调") as FeatureLayer;

                    SpatialReference sr = zdLayer.GetSpatialReference();
                    // 更新地图坐标系
                    map.SetSpatialReference(sr);
                    // 更新图层的源
                    string fcPath = in_fc.TargetLayerPath();
                    GisTool.UpdataLayerSource(zdLayer, fcPath);
                    GisTool.UpdataLayerSource(pointLayer, point);
                    GisTool.UpdataLayerSource(polylineLayer, polyline);

                    // 遍历面要素类中的所有要素
                    using RowCursor rowCursor = zdLayer.Search();
                    while (rowCursor.MoveNext())
                    {
                        using var feature = rowCursor.Current as Feature;
                        Polygon polygon = feature.GetShape() as Polygon;

                        // 获取参数
                        long oid = feature.GetObjectID();
                        string oidField = zdLayer.TargetIDFieldName();

                        string qlr = GetFieldValue(feature, field_qlr);
                        string zddm = GetFieldValue(feature, field_zddm);
                        string tfh = GetFieldValue(feature, field_tfh);
                        string zdmj = GetFieldValue(feature, field_zdmj);

                        pw.AddMessageMiddle(5, $"处理要素：{oid} - 权利人：{qlr}");

                        // 裁剪目标三调数据并更新数据源
                        var queryFilter = new QueryFilter();
                        queryFilter.WhereClause = $"{oidField} = {oid}";
                        zdLayer.Select(queryFilter);
                        string clip = $@"{defGDB}\clip_{oid}";
                        Arcpy.Clip(in_sd, zdLayer, clip);
                        GisTool.UpdataLayerSource(sdLayer, clip);

                        // 计算备注并更新文本标签
                        UpdataBZ(clip, layout);

                        // 更新文本标签
                        UpdataText(layout, "测绘单位", $"{dw}");
                        UpdataText(layout, "制图日期", $"制图日期：{ztsj}");
                        UpdataText(layout, "审核日期", $"审核日期：{shsj}");
                        UpdataText(layout, "制图者", $"制图者：{ztr}");
                        UpdataText(layout, "审核者", $"审核者：{shr}");

                        string jx = ztsj[..(ztsj.LastIndexOf("月") + 1)];
                        UpdataText(layout, "解析法测图", $"{jx}解析法测图");

                        UpdataText(layout, "宗地代码", $"宗地代码：{zddm}");
                        UpdataText(layout, "土地权利人", $"土地权利人：{qlr}");
                        UpdataText(layout, "所在图幅号", $"所在图幅号：{tfh}");
                        UpdataText(layout, "宗地面积", $"宗地面积：{zdmj} ㎡");


                        mf.SetCamera(feature.GetShape().Extent);

                        // 可以调节缩放
                        Camera cam = mf.Camera;
                        double sc = cam.Scale * 1.5;
                        cam.Scale = SetScaleCus(sc);
                        mf.SetCamera(cam);

                        // 只显示当前要素
                        zdLayer.SetDefinitionQuery($"{oidField} = {oid}");
                        pointLayer.SetDefinitionQuery($"原要素编码 = {oid}");
                        polylineLayer.SetDefinitionQuery($"原要素编码 = {oid}");


                        // 复制界址点Excel表
                        string excelPath = @$"{targetFolder}\界址点坐标表_醉.xlsx";
                        DirTool.CopyResourceFile(@"CCTool.Data.Excel.杂七杂八.界址点坐标表_醉.xlsx", excelPath);
                        // 界址点表
                        JZBSB(excelPath, polygon, layout);


                        // 图片属性
                        JPEGFormat JPG = new JPEGFormat()
                        {
                            HasWorldFile = true,
                            Resolution = 300,
                            OutputFileName = @$"{targetFolder}\{oid}.jpg",
                            ColorMode = JPEGColorMode.TwentyFourBitTrueColor,
                        };

                        // 导出图片
                        layout.Export(JPG);

                        // 删除中间数据
                        Arcpy.Delect(clip);

                        // 恢复定义
                        zdLayer.RemoveAllDefinitionQueries();
                    }


                    File.Delete($@"{targetFolder}\界址点坐标表_醉.jpg");
                    File.Delete($@"{targetFolder}\界址点坐标表_醉.xlsx");

                    List<string> files = DirTool.GetAllFiles(targetFolder, ".jgw");
                    foreach (string file in files)
                    {
                        File.Delete(file);
                    }

                    pw.AddMessageEnd();
                });
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.Message + ee.StackTrace);
                return;
            }
        }

        // 计算备注并更新文本标签
        private void UpdataBZ(string clip, Layout layout)
        {
            // 如果相交没有重叠，返回
            if (clip.GetFeatureCount() == 0)
            {
                return;
            }

            string defGDB = Project.Current.DefaultGeodatabasePath;
            string statistics = $@"{defGDB}\statistics";
            Arcpy.Statistics(clip, statistics, "shape_area SUM", "DLMC");
            Dictionary<string, double> dict = GisTool.GetDictFromPathDouble(statistics, "DLMC", "SUM_shape_area");

            string bz = "备注：\r\n\r\n三调数据，其中";
            foreach (var item in dict)
            {
                string mc = item.Key;
                string mj = item.Value.RoundWithFill(2);

                bz += $"{mc}：{mj}平米、";
            }
            string result = bz[..^1] + "。";

            // 更新
            TextElement te = layout.FindElement("备注") as TextElement;
            var a = te.TextProperties;
            te.SetTextProperties(new TextProperties(result, a.Font, a.FontSize, a.FontStyle));

        }


        // 界址标示表
        private void JZBSB(string excelPath, Polygon polygon, Layout layout)
        {
            // 获取工作薄、工作表
            string excelFile = ExcelTool.GetPath(excelPath);
            int sheetIndex = ExcelTool.GetSheetIndex(excelPath);
            // 打开工作薄
            Workbook wb = ExcelTool.OpenWorkbook(excelFile);
            // 处理sheet
            Worksheet ws = wb.Worksheets[sheetIndex];
            Cells cells = ws.Cells;

            int xyDigit = 2;

            // 点号标记
            int dh = 1;

            if (polygon != null)
            {
                // 面积_平方米，亩
                string area_m = polygon.Area.RoundWithFill(2) + "平方米";
                string area_mu = (polygon.Area / 10000 * 15).RoundWithFill(2) + "亩";

                cells[9, 0].Value = $"S={area_m}  合{area_mu}";

                // 获取面要素的所有折点【按西北角起始，顺时针重排】
                List<List<MapPoint>> mapPoints = polygon.ReshotMapPoint();

                int index = 1;   // 起始行

                for (int i = 0; i < mapPoints.Count; i++)
                {
                    // 输出折点的XY值和距离到Excel表
                    double prevX = double.NaN;
                    double prevY = double.NaN;

                    for (int j = 0; j < mapPoints[i].Count - 1; j++)
                    {
                        // 复制行
                        if (index > 5)
                        {
                            cells.InsertRows(index, 2);
                            cells.CopyRows(cells, 3, index, 2);
                            cells.CopyRows(cells, 3, index, 2);
                        }

                        double x = Math.Round(mapPoints[i][j].X, xyDigit);
                        double y = Math.Round(mapPoints[i][j].Y, xyDigit);

                        // 写入折点的XY值
                        cells[index, 1].Value = y;
                        cells[index, 2].Value = x;

                        // 写入点号
                        cells[index, 0].Value = $"J{dh}";

                        // 第一个点的时候，末点给填上
                        if (j == 0)
                        {
                            cells[7, 0].Value = "J1";
                            cells[7, 1].Value = y;
                            cells[7, 2].Value = x;
                        }

                        // 设置单元格为数字型，小数位数
                        Aspose.Cells.Style style = cells[index, 2].GetStyle();
                        style.Number = 4;   // 数字型
                                            // 小数位数
                        style.Custom = xyDigit switch
                        {
                            1 => "0.0",
                            2 => "0.00",
                            3 => "0.000",
                            4 => "0.0000",
                            _ => null,
                        };
                        // 设置
                        cells[index, 1].SetStyle(style);
                        cells[index, 2].SetStyle(style);
                        cells[index + 2, 1].SetStyle(style);
                        cells[index + 2, 2].SetStyle(style);

                        // 计算当前点与上一个点的距离
                        if (!double.IsNaN(prevX) && !double.IsNaN(prevY))
                        {
                            string distance = Math.Sqrt(Math.Pow(x - prevX, 2) + Math.Pow(y - prevY, 2)).RoundWithFill(2);
                            // 写入距离【第一行不写入】
                            cells[index - 1, 3].Value = distance;
                        }
                        prevX = x;
                        prevY = y;

                        index += 2;
                        dh++;
                    }
                }

                // 单元格处理
                cells.UnMerge(6, 0, index - 6 + 1, 1);
                cells.UnMerge(6, 3, index - 6 + 1, 1);

                for (int i = 6; i < index; i += 2)
                {
                    cells.Merge(i, 3, 2, 1);
                }

            }


            // 保存
            wb.Save(excelFile);
            wb.Dispose();

            // 导出图片
            string jpgPath = excelPath.Replace(".xlsx", ".jpg");
            ExcelTool.ImportToJPG(excelPath, jpgPath);

            PictureElement picData = layout.FindElement("界址点表") as PictureElement;          // 获取界址点表
            if (picData is not null)
            {
                layout.DeleteElement(picData);
            }

            // 创建图片【指标图】
            Coordinate2D ll_table = new Coordinate2D(212.1696, 22.1675);
            Coordinate2D ur_table = new Coordinate2D(279.3223, 266.4687);
            Envelope env_table = EnvelopeBuilderEx.CreateEnvelope(ll_table, ur_table);

            ElementFactory.Instance.CreatePictureGraphicElement(layout, env_table.Extent, jpgPath, "界址点表", true, new ElementInfo() { });

        }


        private void btn_help_Click(object sender, RoutedEventArgs e)
        {
            string url = "https://blog.csdn.net/xcc34452366/article/details/149605044";
            UITool.Link2Web(url);
        }


        private void combox_fc_DropClose(object sender, EventArgs e)
        {
            // 更新默认字段
            UpdataField();
        }


        private void combox_tfh_DropDown(object sender, EventArgs e)
        {
            UITool.AddTextFieldsToComboxPlus(combox_fc.ComboxText(), combox_tfh);
        }


        private void combox_zddm_DropDown(object sender, EventArgs e)
        {
            UITool.AddTextFieldsToComboxPlus(combox_fc.ComboxText(), combox_zddm);
        }

        private void combox_qlr_DropDown(object sender, EventArgs e)
        {
            UITool.AddTextFieldsToComboxPlus(combox_fc.ComboxText(), combox_qlr);
        }


        private void combox_zdmj_DropDown(object sender, EventArgs e)
        {
            UITool.AddFloatFieldsToComboxPlus(combox_fc.ComboxText(), combox_zdmj);
        }

        // 加载预设的布局
        private async void btn_addLayout_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                List<string> lyNames = new List<string>()
                {
                    "宗地图",
                };

                await QueuedTask.Run(() =>
                {
                    List<string> layoutNames = GetAllLayoutNames();
                    // 导入之前，为避免存在旧的布局，先移除掉，保证更新
                    // 先移除布局
                    var layoutItems = Project.Current.GetItems<LayoutProjectItem>();
                    foreach (var layoutItem in layoutItems)
                    {
                        if (lyNames.Contains(layoutItem.Name))
                        {
                            Project.Current.RemoveItem(layoutItem);
                        }
                    }

                    // 移除地图
                    var maps = Project.Current.GetItems<MapProjectItem>();
                    foreach (var map in maps)
                    {
                        if (lyNames.Contains(map.Name))
                        {
                            Project.Current.RemoveItem(map);
                        }
                    }

                    // 导入做好的布局模板
                    foreach (string lyName in lyNames)
                    {
                        string pagePath = @$"{Project.Current.HomeFolderPath}\宗地图.pagx";
                        DirTool.CopyResourceFile(@$"CCTool.Data.Layouts.宗地图.pagx", pagePath);
                        IProjectItem pagx = ItemFactory.Instance.Create(pagePath) as IProjectItem;
                        Project.Current.AddItem(pagx);

                        // 删除布局文件
                        File.Delete(pagePath);
                    }
                });
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.Message + ee.StackTrace);
                return;
            }
        }

        // 获取布局名
        private List<string> GetAllLayoutNames()
        {
            List<string> layoutNames = new List<string>();

            // 获取当前工程中的所有LayoutProjectItem
            IEnumerable<LayoutProjectItem> layoutProjects = Project.Current.GetItems<LayoutProjectItem>();

            foreach (LayoutProjectItem layoutProject in layoutProjects)
            {
                // 获取layout 
                Layout layout = layoutProject.GetLayout();

                if (!layoutNames.Contains(layout.Name))
                {
                    layoutNames.Add(layout.Name);
                }
            }

            return layoutNames;
        }

        // 更新文本标签
        private static void UpdataText(Layout layout, string name, string text)
        {
            TextElement te = layout.FindElement(name) as TextElement;

            var a = te.TextProperties;
            te.SetTextProperties(new TextProperties(text, a.Font, a.FontSize, a.FontStyle));
        }

        private void combox_sd_DropDown(object sender, EventArgs e)
        {
            UITool.AddFeatureLayersToComboxPlus(combox_sd);
        }

        // 自适应设置比例
        public static double SetScaleCus(double scale)
        {
            double targetScale = scale;

            if (scale < 100)
            {
                targetScale = 100;
            }
            else if (scale > 100 && scale < 200)
            {
                targetScale = 200;
            }
            else if (scale > 200 && scale < 300)
            {
                targetScale = 300;
            }
            else if (scale > 300 && scale < 500)
            {
                targetScale = 500;
            }
            else if (scale > 500 && scale < 1000)
            {
                targetScale = 1000;
            }
            else if (scale > 1000 && scale < 2000)
            {
                targetScale = 2000;
            }
            else if (scale > 2000 && scale < 3000)
            {
                targetScale = 3000;
            }
            else if (scale > 3000 && scale < 4000)
            {
                targetScale = 4000;
            }
            else if (scale > 4000 && scale < 5000)
            {
                targetScale = 5000;
            }
            else if (scale > 5000 && scale < 8000)
            {
                targetScale = 8000;
            }
            else if (scale > 8000 && scale < 10000)
            {
                targetScale = 10000;
            }
            else
            {
                targetScale = 20000;
            }

            return targetScale;

        }
    }
}
